<?php

/*
 * Fresns (https://fresns.org)
 * Copyright (C) 2021-Present Jarvis Tang
 */

namespace Plugins\FresnsEngine;

use Illuminate\Support\Arr;

class Client
{
    /** @var \GuzzleHttp\Psr7\Response */
    protected $response;
    protected $rawData;
    protected $result;

    public static function create()
    {
        return new static();
    }

    public function client()
    {
        $marketUrl = app()->environment('local') ? config('app.url') : 'https://api.fresns.cn';
        
        $options = [
            'base_uri' => $marketUrl,
            'timeout' => 5, // 请求 5s 超时
            'http_errors' => false,
            'headers' => [
                'Accept' => 'application/json',
            ],
        ];

        return new \GuzzleHttp\Client($options);
    }

    public function getKey(?string $field = null, ?string $key = null)
    {
        $field = $field ?? '';

        if ($field && $key) {
            $field = "$field.$key";
        }

        return $field;
    }

    public function getData(?string $key = null, $default = null)
    {
        return $this->getRaw($this->getKey('data', $key), $default);
    }

    public function paginate()
    {
        if (empty($paginate = $this->getPaginate())) {
            return null;
        }

        $paginate = new \Illuminate\Pagination\LengthAwarePaginator(
            items: $this->getList(),
            total: $paginate['total'],
            perPage: $paginate['pageSize'],
            currentPage: $paginate['currentPage'],
        );

        $paginate
            ->withPath('/'.\request()->path())
            ->withQueryString();

        return $paginate;
    }

    public function getDetail(?string $key = null, $default = null)
    {
        return Arr::get($this->result, $this->getKey('detail', $key), $default);
    }

    public function getPaginate(?string $key = null, $default = null)
    {
        return Arr::get($this->result, $this->getKey('paginate', $key), $default);
    }

    public function getList(?string $key = null, $default = null)
    {
        return Arr::get($this->result, $this->getKey('lists', $key), $default);
    }

    public function getRaw(?string $key = null, $default = null)
    {
        if ($key = $this->getKey($key)) {
            return Arr::get($this->rawData, $this->getKey($key), $default);
        }

        return $this->rawData;
    }

    protected function castResponse()
    {
        $this->rawData = json_decode($content = $this->response->getBody()->getContents(), true) ?? [];

        if (empty($this->getRaw())) {
            info('empty reponse, ApiException: '.var_export($content, true));
            throw new \Exception(sprintf('ApiException: %s', $this->response->getReasonPhrase()), $this->response->getStatusCode());
        }

        if ($this->getRaw('code') !== 0) {
            info('error reponse, ApiException: '.var_export($content, true));
            throw new \Exception(sprintf('ApiException: %s', $this->getRaw('msg', $this->getRaw('exception'))), $this->getRaw('code'));
        }

        return $this->getRaw('data') ?? $this->getRaw();
    }

    public function __call($method, $args)
    {
        $this->response = $this->client()->$method(...$args);

        $this->result = $this->castResponse();

        return $this;
    }
}
